package com.jdcjk.util;

import android.content.Context;

import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.model.LatLng;
import com.amap.api.services.poisearch.PoiSearch;
import com.jdcjk.MainApp;
import com.jdcjk.project.car.model.entity.TerminalPathBean;

import java.util.List;

import static com.jdcjk.util.BaiDuMapUtil.outOfChina;

/**
 * Created by Administrator on 2016/12/12 0012.
 */

public class GaoDeMapUtil {
    //声明AMapLocationClient类对象
    public static AMapLocationClient mLocationClient = null;
    //声明AMapLocationClientOption对象
    public static AMapLocationClientOption mLocationOption = null;
    public static double pi = 3.1415926535897932384626;
    public static double a = 6378245.0;
    public static double ee = 0.00669342162296594323;

    /**
     * 获得城市city，to位置的位置信息
     *
     * @param context
     * @param to                  位置
     * @param city                城市
     * @param onPoiSearchListener 回调接口，可获得位置信息
     */
    public static void getLocation(Context context, String to, String city, PoiSearch.OnPoiSearchListener onPoiSearchListener) {
        PoiSearch.Query query = new PoiSearch.Query(to.trim(), "", city);
        //keyWord表示搜索字符串，
        //第二个参数表示POI搜索类型，二者选填其一，
        //POI搜索类型共分为以下20种：汽车服务|汽车销售|
        //汽车维修|摩托车服务|餐饮服务|购物服务|生活服务|体育休闲服务|医疗保健服务|
        //住宿服务|风景名胜|商务住宅|政府机构及社会团体|科教文化服务|交通设施服务|
        //金融保险服务|公司企业|道路附属设施|地名地址信息|公共设施
        //cityCode表示POI搜索区域，可以是城市编码也可以是城市名称，也可以传空字符串，空字符串代表全国在全国范围内进行搜索
        query.setPageSize(1);// 设置每页最多返回多少条poiitem
        final PoiSearch poiSearch = new PoiSearch(context, query);
        poiSearch.setOnPoiSearchListener(onPoiSearchListener);
        poiSearch.searchPOIAsyn();
    }

    /**
     * 获得当前位置
     *
     * @param mLocationListener 回调接口，可以获得对应的位置信息
     */
    public static void getLocation(AMapLocationListener mLocationListener) {
        //初始化定位
        mLocationClient = new AMapLocationClient(MainApp.getInstance());
        //设置定位回调监听
        mLocationClient.setLocationListener(mLocationListener);
        //初始化AMapLocationClientOption对象
        mLocationOption = new AMapLocationClientOption();
        //高精度定位模式：会同时使用网络定位和GPS定位，优先返回最高精度的定位结果，以及对应的地址描述信息。
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
        //低功耗定位模式：不会使用GPS和其他传感器，只会使用网络定位（Wi-Fi和基站定位）；
//        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving);
        //仅用设备定位模式：不需要连接网络，只使用GPS进行定位，这种模式下不支持室内环境的定位，自 v2.9.0 版本支持返回地址描述信息。
//        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Device_Sensors);
        //获取一次定位结果：
        //该方法默认为false。
        mLocationOption.setOnceLocation(true);

        //获取最近3s内精度最高的一次定位结果：
        //设置setOnceLocationLatest(boolean b)接口为true，启动定位时SDK会返回最近3s内精度最高的一次定位结果。
        // 如果设置其为true，setOnceLocation(boolean b)接口也会被设置为true，反之不会，默认为false。
        mLocationOption.setOnceLocationLatest(true);
        //设置定位间隔,单位毫秒,默认为2000ms，最低1000ms。
        mLocationOption.setInterval(1000);
        //设置是否返回地址信息（默认返回地址信息）
        mLocationOption.setNeedAddress(false);
        //设置是否允许模拟位置,默认为false，不允许模拟位置
        mLocationOption.setMockEnable(false);
        //单位是毫秒，默认30000毫秒，建议超时时间不要低于8000毫秒。
        mLocationOption.setHttpTimeOut(20000);
        //缓存机制默认开启，可以通过以下接口进行关闭。
        //当开启定位缓存功能，在高精度模式和低功耗模式下进行的网络定位结果均会生成本地缓存，
        // 不区分单次定位还是连续定位。GPS定位结果不会被缓存。
        // 关闭缓存机制
        mLocationOption.setLocationCacheEnable(false);
        //给定位客户端对象设置定位参数
        mLocationClient.setLocationOption(mLocationOption);
        //启动定位
        mLocationClient.startLocation();
    }

    /**
     * 根据距离返回高德地图缩放登记
     *
     * @param distance 起点与终点之间的距离
     * @return 缩放等级
     */
    public static float getZoomLevelByDistance(float distance) {
        float zoomLevel = 14;
        distance = Math.abs(distance);
        if (distance >= 0 && distance <= 50) {
            zoomLevel = 19;
        } else if (distance > 50 && distance <= 200) {
            zoomLevel = 18;
        } else if (distance > 200 && distance <= 1000) {
            zoomLevel = 17;
        } else if (distance > 1000 && distance <= 5000) {
            zoomLevel = 15;
        } else if (distance > 5000 && distance <= 10000) {
            zoomLevel = 13;
        } else if (distance > 10000 && distance <= 50000) {
            zoomLevel = 12;
        } else if (distance > 50000 && distance <= 100000) {
            zoomLevel = 10;
        } else if (distance > 100000 && distance <= 500000) {
            zoomLevel = 8;
        } else if (distance > 500000 && distance <= 1000000) {
            zoomLevel = 6;
        } else if (distance > 10000000 && distance <= 5000000) {
            zoomLevel = 5;
        } else {
            zoomLevel = 3;
        }
        return zoomLevel;
    }

    /**
     * 将地球坐标系（WGS84） 转换成高德坐标系 (GCJ-02)
     *
     * @param latLng
     * @return
     */
    public static LatLng gaodeLatLngEncrypt(LatLng latLng) {
        double lon = latLng.longitude, lat = latLng.latitude;
        double dLat = transformLat(lon - 105.0, lat - 35.0);
        double dLon = transformLon(lon - 105.0, lat - 35.0);
        double radLat = lat / 180.0 * Math.PI;
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * Math.PI);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * Math.PI);
        double mgLat = lat + dLat;
        double mgLon = lon + dLon;

        return new LatLng(mgLat, mgLon, true);
    }

    /**
     * 将地球坐标系（WGS84） 转换成高德坐标系 (GCJ-02)
     * 高精度时，不验证坐标是否合理
     *
     * @param latLng
     * @return
     */
    public static LatLng gjdGaodeLatLngEncrypt(LatLng latLng) {
        double lon = latLng.longitude, lat = latLng.latitude;
        double dLat = transformLat(lon - 105.0, lat - 35.0);
        double dLon = transformLon(lon - 105.0, lat - 35.0);
        double radLat = lat / 180.0 * Math.PI;
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * Math.PI);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * Math.PI);
        double mgLat = lat + dLat;
        double mgLon = lon + dLon;

        return new LatLng(mgLat, mgLon, false);
    }

    public static LatLng transform(double lat, double lon) {
        if (outOfChina(lat, lon)) {
            return new LatLng(lat, lon);
        }
        double dLat = transformLat(lon - 105.0, lat - 35.0);
        double dLon = transformLon(lon - 105.0, lat - 35.0);
        double radLat = lat / 180.0 * pi;
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
        double mgLat = lat + dLat;
        double mgLon = lon + dLon;
        return new LatLng(mgLat, mgLon);
    }

    public static double transformLat(double x, double y) {
        double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
                + 0.2 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0;
        return ret;
    }

    public static double transformLon(double x, double y) {
        double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
                * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0
                * Math.PI)) * 2.0 / 3.0;
        return ret;
    }

    /**
     * 将地球坐标系（WGS84）集合 转换成高德坐标系(GCJ-02)集合
     *
     * @param latLngList
     * @return
     */
    public static List<LatLng> gaodeLatLngListEncrypt(List<LatLng> latLngList) {
        for (int i = 0; i < latLngList.size(); i++) {
            latLngList.set(i, gaodeLatLngEncrypt(latLngList.get(i)));
        }
        return latLngList;
    }

    /**
     * 将高德坐标系 (GCJ-02) to 地球坐标系（WGS84）@param lon * @param lat * @return
     */
    public static LatLng gcj_To_Gps84(LatLng latLng) {
        LatLng latLng84 = transform(latLng.latitude, latLng.longitude);
        double lontitude = latLng.longitude * 2 - latLng84.longitude;
        double latitude = latLng.latitude * 2 - latLng84.latitude;
        return new LatLng(latitude, lontitude);
    }

    /**
     * 将轨迹回放中的坐标系集合 (WGS84) 转换成高德坐标系 (GCJ-02)集合
     *
     * @param terminalPathBeanList 轨迹点list
     * @param isHighPrecision      是否为高精度（高精度则不判断坐标是否合法，防止精度丢失）
     * @return
     */
    public static List<TerminalPathBean> gaodeTerminalPathListEncrypt(List<TerminalPathBean> terminalPathBeanList, boolean isHighPrecision) {
        if (isHighPrecision) {
            //高精度时
            for (int i = 0; i < terminalPathBeanList.size(); i++) {
                LatLng gaodeLatLng = new LatLng(terminalPathBeanList.get(i).getLatitude(), terminalPathBeanList.get(i).getLongitude(), false);
                gaodeLatLng = gjdGaodeLatLngEncrypt(gaodeLatLng);
                terminalPathBeanList.get(i).setLatLng(gaodeLatLng.latitude, gaodeLatLng.longitude);
            }
        } else {
            //非高精度时
            for (int i = 0; i < terminalPathBeanList.size(); i++) {
                LatLng gaodeLatLng = new LatLng(terminalPathBeanList.get(i).getLatitude(), terminalPathBeanList.get(i).getLongitude(), true);
                gaodeLatLng = gaodeLatLngEncrypt(gaodeLatLng);
                terminalPathBeanList.get(i).setLatLng(gaodeLatLng.latitude, gaodeLatLng.longitude);
            }
        }
        return terminalPathBeanList;
    }


    /**
     * 设定方向值
     * 分为十六个方向
     * 1-45为右上22°
     * 45-89为右上45°
     * 91-179为左上45°，即135°
     * 181-269为左下45°，即225°
     * 271-359为右下右下45°，即315°
     * 其余为上下左右，即90°，270°，180°，360°（0°）
     *
     * @param direction
     * @return
     */
    public static float setDirection(float direction) {
        float degree = 0;
        if (direction == 0 || direction == 360) {
            degree = 0;
        } else if (direction == 90) {
            degree = 22;
        } else if (direction == 180) {
            degree = 180;
        } else if (direction == 270) {
            degree = 270;
        } else if (direction >= 1 && direction <= 89) {
            degree = 45;
        } else if (direction >= 91 && direction <= 179) {
            degree = 135;
        } else if (direction >= 181 && direction <= 269) {
            degree = 225;
        } else if (direction >= 271 && direction <= 359) {
            degree = 315;
        }
        return degree;
    }


    /**
     * 计算两坐标之间的角度
     *
     * @param latLngOne 坐标1
     * @param latLngTwo 坐标2
     * @return
     */
    public static float coordinatesAngleCalculation(LatLng latLngOne, LatLng latLngTwo) {
        double a, b, R;
        R = 6378137; // 地球半径
        double lat1 = latLngOne.latitude;
        double lat2 = latLngTwo.latitude;
        lat1 = lat1 * Math.PI / 180.0;
        lat2 = lat2 * Math.PI / 180.0;
        a = lat1 - lat2;
        double long1 = latLngOne.longitude;
        double long2 = latLngTwo.longitude;
        b = (long1 - long2) * Math.PI / 180.0;
        float angle;
        double sa2, sb2;
        sa2 = Math.sin(a / 2.0);
        sb2 = Math.sin(b / 2.0);
        angle = (float) (2 * R * Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1) * Math.cos(lat2) * sb2 * sb2)));
        if (long2 < long1)
            angle += 90;
        return angle;
    }
}
